﻿using System;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Data;
using System.Windows.Threading;
using MapInfo.Wrapper.Extensions.TenFive;
using MapInfo.Wrapper.Mapinfo;
using MapInfo.Wrapper.MapOperations;
using NathansMapInfoProjects.WindowManager.ViewModels;
using System.Windows.Interop;
using NathansMapInfoProjects.WindowManager.Views;
using Window = MapInfo.Wrapper.MapOperations.Window;
using WindowCollection = System.Windows.WindowCollection;

namespace NathansMapInfoProjects.WindowManager
{
    public static class InteropHelper
    {
        private const int SYS_INFO_APPVERSION = 2; // Used with SystemInfo to get appversion

        /// <summary>
        /// Gets the MapInfo Professional version number
        /// </summary>
        /// <returns>Version number (multiplied by 100) as string</returns>
        public static string GetAppVersion()
        {
            string expr = string.Format("SystemInfo({0})", SYS_INFO_APPVERSION);
            return Entry.Session.Eval(expr);
        }
    }

    public static class Entry
    {
        public static event Action<Window> WindowClosed;
        public static event Action<Window> WindowFocusChanged;

        private static MapInfoSession _session;
        public static MapInfoSession Session
        {
            get
            {
                if (Entry._session == null)
                {
                    Entry._session = (MapInfoSession)MapInfoSession.GetLoadedInstance();
                }
                return Entry._session;
            }
        }

        private static ShellView shell;

        public static Settings settings;

        public static Settings LoadSettings()
        {
            if (settings == null)
            {
                string path = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + "\\MapInfo\\MapInfo\\nathansmapinfoprojects.windowmanager.xml";
                Entry.settings = Settings.LoadSettings(path);
            }
            return Entry.settings;
        }

        public static void AutoLoad()
        {
            Entry.LoadSettings();
            if (settings.AutoLoad)
            {
                Entry.Load();
            }
        }

        /// <summary>
        /// The entry point from the WindowManager.mbx, this is called when the Window Manager dialog needs to 
        /// be shown to the user.
        /// </summary>
        public static void Load()
        {
            if (shell == null)
            {
                Entry.shell = CreateShell();
                Status = ShownUsing.Closed;

                if (Session.Eval("SystemInfo(3)") == "1050")
                {
                    HwndSource hwndSource = CreateHwndSource(Session.SystemInfo.MapinfoFrameHandle);
                    hwndSource.RootVisual = shell;
                    hwndSource.SizeToContent = SizeToContent.Manual;

                    dockwindow = Session.RegisterDockWindow(hwndSource.Handle);
                    dockwindow.Title = "Window Manager";
                    dockwindow.Dock(DockPosition.PositionRight, 200, 200);
                    Status = ShownUsing.Dock;
                }
            }

            if (Status == ShownUsing.Dock && dockwindow.Closed)
            {
                dockwindow.Activate();
                Status = ShownUsing.Dock;
            }
            else if (Status == ShownUsing.Window && ShellWindow != null)
            {
                ShellWindow.Show();
                Status = ShownUsing.Window;
            }
            else if (Status == ShownUsing.Closed && ShellWindow == null)
            {
                ShellWindow = new System.Windows.Window();
                ShellWindow.Content = shell;
                ShellWindow.Closing += ShellWindowClosing;
                WindowInteropHelper helper = new WindowInteropHelper(ShellWindow);
                helper.Owner = Session.SystemInfo.MapinfoFrameHandle;
                ShellWindow.Height = settings.Height;
                ShellWindow.Width = settings.Width;
                ShellWindow.Top = settings.Top;
                ShellWindow.Left = settings.Left;
                ShellWindow.Title = "Window Manager";
                ShellWindow.ShowInTaskbar = false;
                ShellWindow.WindowStyle = WindowStyle.ToolWindow;
                ShellWindow.Show();
                Status = ShownUsing.Window;
            }
        }


        enum ShownUsing
        {
            Dock,
            Window,
            Closed
        }

        private static ShownUsing Status { get; set; }

        public static System.Windows.Window ShellWindow { get; set; }

        private static ShellView CreateShell()
        {
            var groups = new List<GroupViewModel>
                             {
                                 new GroupViewModel("Maps", new[] {WindowTypes.mapper}),
                                 new GroupViewModel("Browsers", new[] {WindowTypes.Browser}),
                                 new GroupViewModel("Layouts", new[] {WindowTypes.Layout}),
                                 new GroupViewModel("Legends",
                                                    new[] {WindowTypes.Legend, WindowTypes.Cart_Legend}),
                                 new GroupViewModel("Graphs", new[] {WindowTypes.Graph}),
                                 new GroupViewModel("Special",
                                                    new[] {WindowTypes.Mapbasic, WindowTypes.Statistics})
                             };

            OpenWindowsViewModel openWindowsViewModel = new OpenWindowsViewModel(groups);
            ClosedWindowsViewModel closedWindowsViewModel = new ClosedWindowsViewModel();
            SettingsViewModel settingsviewmodel = new SettingsViewModel(Entry.settings);

            ShellViewModel vm = new ShellViewModel(openWindowsViewModel, closedWindowsViewModel,
                                                   settingsviewmodel, Entry.settings);
            return new ShellView(vm);
        }

        private static DockWindow dockwindow { get; set; }

        private static HwndSource CreateHwndSource(IntPtr hParent)
        {
            HwndSourceParameters parameters = new HwndSourceParameters
            {
                PositionX = 100,
                PositionY = 200,
                Height = 0x3e8,
                Width = 450,
                ParentWindow = hParent,
                WindowStyle = 0x40000000,
                UsesPerPixelOpacity = false
            };
            return new HwndSource(parameters);
        }

        static void ShellWindowClosing(object sender, System.ComponentModel.CancelEventArgs e)
        {
            Settings.SaveSettings(Entry.settings, Entry.settings.LoadedFrom);

            e.Cancel = true;

            System.Windows.Window window = ((System.Windows.Window)sender);
            window.Dispatcher.BeginInvoke(DispatcherPriority.Background, (DispatcherOperationCallback)delegate
                                                                                                          {
                                                                                                              window.Hide();
                                                                                                              return null;
                                                                                                          }, null);
        }

        /// <summary>
        /// Handler for the window closed event from MapInfo.
        /// </summary>
        /// <param name="Id">The ID of the window that was closed.</param>
        /// <remarks>This method is called from the WindowManager.MBX directly.</remarks>
        public static void OnWindowClosed(int Id)
        {
            if (WindowClosed != null)
            {
                Window window = new Window(Id, Entry.Session);
                WindowClosed(window);
            }

        }

        /// <summary>
        /// Handler for the window fouces changed event from MapInfo.
        /// </summary>
        /// <param name="Id">The ID of the window that lost focus.</param>
        /// <remarks>This method is called from the WindowManager.MBX directly.</remarks>
        public static void OnWindowFocusChanged(int id)
        {
            if (WindowFocusChanged != null)
            {
                Window window = new Window(id, Entry.Session);
                WindowFocusChanged(window);
            }
        }
    }
}
